package com.lyn.utils;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 外网监听器
 * @author longyn 2023/4/27
 * @version 1.0.0
 */
public class NetworkUtil {

    private static final class NetworkUtilTypeClass {
        private static final NetworkUtil in = new NetworkUtil();
    }

    public static NetworkUtil getInstance() {
        return NetworkUtilTypeClass.in;
    }

    private static final String TAG = "NetworkUtil";

    private boolean debug;

    public boolean isDebug() {
        return debug;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    private static boolean extranet = true;

    private final Handler handler = new Handler(Looper.getMainLooper());

    private final static Object lock = new Object();


    public NetworkUtil() {
        new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    try {
                        lock.wait(1000);
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                }
                boolean existNetwork = false;
                for (int i = 0; i < 5; i++) {
                    PingData pingData = ping();
                    if (pingData != null && pingData.success) {
                        handler.post(() -> {
                            if (listener != null) {
                                listener.onMs(pingData.ms);
                            }
                        });
                        existNetwork = true;
                        break;
                    }
                    handler.post(() -> {
                        if (listener != null) {
                            listener.onMs(-1L);
                        }
                    });
                }
                if (extranet != existNetwork) {
                    boolean finalExistNetwork = existNetwork;
                    handler.post(() -> {
                        if (listener != null) {
                            listener.onChange(finalExistNetwork);
                        }
                    });
                }
                extranet = existNetwork;
            }
        }).start();
    }

    private long getMs(String input) {
        try {
            Pattern pattern = Pattern.compile("time=(\\d+)");
            Matcher matcher = pattern.matcher(input);
            if (matcher.find()) {
                return Long.parseLong(Objects.requireNonNull(matcher.group(1)));
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return 0L;
    }


    private PingData ping() {
        Process process = null;
        BufferedReader reader = null;
        try {
            process = Runtime.getRuntime().exec("ping -c 1 www.baidu.com");
            long startTime = System.nanoTime();
            long timeout = 1500;
            long rem = TimeUnit.MILLISECONDS.toNanos(timeout);
            do {
                try {
                    process.exitValue();
                    break;
                } catch(IllegalThreadStateException ex) {
                    if (rem > 0)
                        Thread.sleep(
                                Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
                }
                rem = TimeUnit.MILLISECONDS.toNanos(timeout) - (System.nanoTime() - startTime);
            } while (rem > 0);
            reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String readLine;
            while ((readLine = reader.readLine()) != null) {
                sb.append(readLine).append("\n");
            }
            String value = sb.toString();
            boolean success = false;
            if (!TextUtils.isEmpty(value)) {
                if (value.contains("ttl")) {
                    success = true;
                }
            }
            long ms = getMs(value);
            return new PingData(success, ms, value);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
            try {
                if (process != null) {
                    process.destroy();
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static class PingData {

        public boolean success;

        public long ms;

        public String result;

        public PingData(boolean success, long ms, String result) {
            this.success = success;
            this.ms = ms;
            this.result = result;
        }
    }


    private NetworkListener listener;

    public void setListener(NetworkListener listener) {
        this.listener = listener;
    }

    /**
     * 是否有外网
     */
    public boolean isExtranet() {
        return extranet;
    }


    public interface NetworkListener {

        void onChange(boolean enabled);

        void onMs(long ms);
    }
}